package org.biodas.jdas.client;

import org.apache.log4j.Logger;
import org.biodas.jdas.dassources.utils.DasSpec;
import org.biodas.jdas.exceptions.DASClientException;
import org.biodas.jdas.exceptions.ValidationException;
import org.biodas.jdas.schema.sources.SOURCES;
import org.springframework.http.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * We have an interface for these clients so that if someone prefers they can use a different implementation e.g. JAXB instead of Spring REST
 * Runnable so we can have multiple threads and concurrancy management
 * LPGL
 *@author JWarren
 *
 */
public class SourcesClient implements SourcesClientInterface{
    private static Logger logger = Logger.getLogger(SourcesClient.class);
	private SOURCES sources;
	RestTemplate restTemp=new RestTemplate();
	private HttpHeaders respHeaders;

	public HttpHeaders getRespHeaders() {
		return respHeaders;
	}


	public SOURCES getSources(){
		return this.sources;
	}
	
	
	@Override
	public SOURCES fetchData(String serverURL) throws ValidationException, DASClientException {
		SOURCES dasSources=null;
//		sources=restTemp.getForObject(serverURL, SOURCES.class);
//		return sources;
		//this is much shorter than the equivalent in JAXB below
//		JAXBContext jc;
//		try {
//			jc = JAXBContext.newInstance("org.biodas.jdas.schema.sources");
//        Unmarshaller unmarshaller;
//			unmarshaller = jc.createUnmarshaller();
//        
//			dasSources = (SOURCES) unmarshaller.unmarshal(new URL(serverURL));
//		} catch (MalformedURLException e) {
//			e.printStackTrace();
//		} catch (JAXBException e) {

//			e.printStackTrace();
//		}
		logger.debug("getting sources from url="+serverURL);
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_XML);
		headers.set(DasHeadersEnum.X_DAS_VERSION.toString(), DasSpec.SPEC1_6E.toString());
//		List<String> acceptableMediaTypes=new ArrayList<String>();
//		acceptableMediaTypes.add(MediaType.APPLICATION_XML.);
//		headers.setAccept(acceptableMediaTypes)
		HttpEntity<String> entity = new HttpEntity(headers);
		ResponseEntity<SOURCES> response;
		try {
			response = restTemp.exchange(serverURL, HttpMethod.GET, entity, SOURCES.class);
		} catch (RestClientException e) {
			
			throw new DASClientException(e.getMessage(), e.getCause());
		}
		respHeaders=response.getHeaders();
		//this.printHeaders();
		dasSources=response.getBody();
		
        return dasSources;
	}

	 /**
     * Retrieves the sources for a server, arguments allowed.
     * @param serverURL
     * @param capability
     * @param type
     * @param authority
     * @param version
     * @param organism
     * @param label
     * @return
	 * @throws Exception 
     */
    public SOURCES fetchDataRegistry(String serverURL, String capability, String type
            , String authority, String version, String organism, String label) throws ValidationException, DASClientException {

        String url = serverURL + "/sources";
        String arguments = null;

        if (capability != null) {
            arguments = "capability=" + capability;
        }
        if (type != null) {
            arguments = arguments == null ? "type=" + type : arguments + "&type=" + type;
        }
        if (authority != null) {
            arguments = arguments == null ? "authority=" + authority : arguments + "&authority=" + authority;
        }
        if (version != null) {
            arguments = arguments == null ? "version=" + version : arguments + "&version=" + version;
        }
        if (organism != null) {
            arguments = arguments == null ? "organism=" + organism : arguments + "&organism=" + organism;
        }
        if (label != null) {
            arguments = arguments == null ? "label=" + label : arguments + "&label=" + label;
        }

        if (arguments != null) {
            url = url + "?" + arguments;
        }
        return this.fetchData(url);
    }  
    
    
    public SOURCES postSource(SOURCES sources, String user, String pass) throws DASClientException{
    	return this.postSource(sources, user, pass, "http://www.dasregistry.org/das/sources/");
    }

    /**
     * Post a sources object that contains only 1 source as at the moment the registry only accepts one at a time.
     * @param sourcesToCreate
     * @param user
     * @param pass
     * @param registrySourcesUrl
     * @return
     * @throws DASClientException
     */
    public SOURCES postSource(SOURCES sourcesToCreate, String user, String pass, String registrySourcesUrl) throws DASClientException{
    	HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_XML);
		
		HttpEntity<String> entity = new HttpEntity(sourcesToCreate, headers);

		ResponseEntity<SOURCES> responseBody = null;
		try {
			responseBody = restTemp.exchange(registrySourcesUrl,
					HttpMethod.POST, entity, SOURCES.class);
		} catch (HttpClientErrorException e) {
			throw new DASClientException(e.getMessage(), e.getCause());
		}	
		logger.info(responseBody.getStatusCode());
        if (!"201".equals(responseBody.getStatusCode().toString())) {
            throw new DASClientException("The response HTML code was not 201");
        }
		SOURCES sources = responseBody.getBody();
		return sources;
    	
    }


	/**
	 * Get DAS version from the headers
	 */
	public DasSpec getDasVersion() {
		HttpHeaders respHeaders = this.getRespHeaders();
		List<String> version = null;
        if(respHeaders.containsKey(DasHeadersEnum.X_DAS_VERSION.toString())){
			 version=respHeaders.get(DasHeadersEnum.X_DAS_VERSION.toString());
			 System.out.println(version.get(0));
			 return DasSpec.convertToRegistrySpecification(version.get(0));
			
			
		}
        return DasSpec.SPEC1_53E;
		
	}
	
	private void printHeaders(){
		Set<String> keyset = respHeaders.keySet();
		for(String key:keyset){
			System.out.println("header key "+ key+ "="+respHeaders.get(key));
		}
		
	}

}
